# -*- coding: utf-8 -*-
# @Author: long
# @Date:   2017-12-18 06:21:04
# @Last Modified by:   ystlong
# @Last Modified time: 2017-12-23 09:05:05

import time
import socket
from HookUtil import ProxyThreadPool, delay
import HookProxy
import HookUtil

class HookClient(object):
	"""docstring for HookClient"""
	def __init__(self, server_config, target_config):
		super(HookClient, self).__init__()
		self.server_config = server_config
		self.target_config = target_config
		self.buffsize = 2048
		self.on = True
		self.socket = None

	def new_target_socket(self):
		target_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		target_addr = (self.target_config["host"], self.target_config["port"])
		target_socket.connect(target_addr)
		return target_socket

	def tunnel_target(self, serve_socket):
		def runable():
			target_socket = self.new_target_socket()
			hp = HookProxy.HookProxy(serve_socket, target_socket)
			hp.start()
		ProxyThreadPool.new_thread(runable)

	def new_hook_socket(self):
		new_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		server_addr = (self.server_config["host"], self.server_config["port"])
		new_socket.connect(server_addr)
		return new_socket

	def dispatch_data(self, master_socket, data):
		if data.strip().startswith("hook-socket:"):
			new_socket = self.new_hook_socket()
			new_socket.send(data)
			data = new_socket.recv(self.buffsize)
			if data == "hook-ack":
				self.tunnel_target(new_socket)
			elif data == "hook-heart":
				self.heart_online = True
			master_socket.send("hook-ack")

	def start_master(self):
		self.heart()
		while True:
			try:
				self._start_master()
			except Exception as e:
				print(repr(e))
				# raise e
			HookUtil.delay(5000)
			print("retry again")

	def _start_master(self):
		self.socket = self.new_hook_socket()
		self.socket.send("hook-master")
		data = self.socket.recv(self.buffsize)
		if data != "hook-ack":
			HookUtil.clean_socket(self.socket)
			# self.socket.close()
			return

		print "===start master ok====="
		while self.on:
			data = self.socket.recv(self.buffsize)
			print "=====master recv data====", data
			self.dispatch_data(self.socket, data)
			if not data:
				break

	def close(self):
		self.on = False
		HookUtil.clean_socket(self.socket)

	def client_heart_cmd(self):
		try:
			self.socket.send("hook-heart")
		except Exception as e:
			# raise e
			pass

	def heart(self):
		def check_heart():
			while True:
				reconn_timeout = 120
				cnt = 0
				self.heart_online = False
				for i in xrange(reconn_timeout):
					self.client_heart_cmd()
					HookUtil.delay(10000)
					if self.heart_online:
						break
				if not self.heart_online:
					self.close()
				HookUtil.delay(10*10000)
		ProxyThreadPool.new_thread(check_heart)

class ProxyManager(object):
	"""docstring for ProxyManager"""
	def __init__(self):
		super(ProxyManager, self).__init__()
		# self.server_config = {"host": "127.0.0.1", "port": 1887}
		self.server_config = {"host": "www.koyst.com", "port": 1887}
		self.target_configs = [
			{"name":"xxxx", 
			"host":"192.168.3.23", 
			# "port": 10000,
			"port": 8080,
			"count": 1
			}]


	def start(self):
		for t_config in self.target_configs:
			client = HookClient(self.server_config, t_config)
			client.start_master()

hc = ProxyManager()
hc.start()
